package com.kyrie.security.shiro;

import com.kyrie.security.jwt.JWTToken;
import com.kyrie.security.jwt.JWTUtil;
import com.kyrie.system.mybatis.service.IDefaultService;
import com.kyrie.utils.ConvertUtils;
import com.kyrie.vo.UserInfoVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/***
 * 描述: 自定义ShiroRealm
 *
 * @author wuxiang
 * @date 2020-04-07 14:06
 */
@Component
public class ShiroRealm extends AuthorizingRealm {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource(name = "defaultService")
    private IDefaultService service;

    /**
     * 重写此方法
     * 标识这个Realm是专门用来验证JwtToken,不负责验证其他的token（UsernamePasswordToken）
     * @param token AuthenticationToken
     * @return boolean
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        //这个token就是从过滤器中传入的jwtToken
        return token instanceof JWTToken;
    }

    /**
     * 用户身份认证
     * @param authenticationToken AuthenticationToken
     * @return AuthenticationInfo
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("##########执行用户身份认证##########");
        // 获取token
        String token = (String) authenticationToken.getCredentials();
        // 通过token获取用户信息
        String user = JWTUtil.getUserInfo(token);

        if (StringUtils.isEmpty(user) || !JWTUtil.verify(token,user)) {
            throw new AuthenticationException("token认证失败！");
        }

        // 执行数据库认证，即双重认证用户身份，防止管理员中途更改用户信息导致用户未重新登录，更改信息不生效
        // TODO 存在问题：中途管理员修改密码怎么办？
        /*UserInfoVO userInfoVO = service.selectOne(NAME_SPACE + "getUserInfo",userNo);
        if (null == userInfoVO) {
            throw new AuthenticationException("用户信息不存在或者被更改，请重新登录");
        }*/

        return new SimpleAuthenticationInfo(token,token,"ShiroRealm");
    }

    /**
     * 用户权限认证
     * @param principals PrincipalCollection
     * @return AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        logger.info("##########执行用户权限认证##########");
        // 获取token中的用户实体信息
        UserInfoVO userInfo = ConvertUtils.stringToBean(JWTUtil.getUserInfo(principals.toString()),UserInfoVO.class);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        String role = userInfo.getRoleSign();
        if (StringUtils.isNotEmpty(role)) {
            simpleAuthorizationInfo.addRole(role);
        }
        logger.info("#####当前用户: {},的角色权限为: {}", userInfo.getUserNo(), role);
        return simpleAuthorizationInfo;
    }


}
